using OpenTK;
using OpenTK.Graphics.OpenGL;

namespace ColladaDotNet.OpenTKMapping
{
	public class MeshItem : DocumentLibraryElement, IPositionSource
	{
		protected int[] indices;

		private BindedSource vertex;

		private BindedSource normal;
		private BindedSource tangent;
		private BindedSource binormal;

		private BindedSource texCoord;

		protected ulong count;

		protected ulong stride;

		public virtual string Material
		{
			get
			{
				return null;
			}
		}


		public virtual void Begin()
		{
			GL.Begin(BeginMode.Triangles);

		}
		public virtual void End()
		{
			GL.End();
			Utils.CheckError();
		}
	
		public virtual void Render()
		{
			Render(this);
		}
		public virtual Vector3 Normal(ulong i)
		{
			if (NormalSource != null)
				return NormalSource.Source.GetVector3(i);
			return Vector3.UnitZ;
		}

		public ulong NumPositions
		{
			get
			{
				return (ulong)indices.Length / stride;
			}
		}

		public BindedSource VertexSource
		{
			get
			{
				return vertex;
			}
		}



		public BindedSource TexCoordSource
		{
			get
			{
				return texCoord;
			}
			set
			{
				texCoord = value;
			}
		}

		public BindedSource NormalSource
		{
			get
			{
				return normal;
			}
		}

		protected void BindInputs(InputLocalOffset[] c)
		{
			stride = 1;
			foreach (InputLocalOffset localOffset in c)
			{
				var s = Document.CreateElement<BindedSource>(localOffset);
				if (s.Offset >= stride)
					stride = s.Offset + 1;
				switch (localOffset.semantic)
				{
					case "VERTEX":
						vertex = s;
						break;
					case "NORMAL":
						normal = s;
						break;
					case "TEXTANGENT":
						tangent = s;
						break;
					case "TEXBINORMAL":
						binormal = s;
						break;
					case "TEXCOORD":
						texCoord = s;
						break;
				}
			}
		}
		public virtual Vector3 Position(ulong i)
		{
			return vertex.Source.GetVector3(i);
		}

		public void Render(IPositionSource positions)
		{
			if (vertex == null)
				return;

			Begin();

			for (ulong i = 0; i < NumPositions; ++i)
			{
				var index1 = (texCoord==null)?0:((i) * stride + texCoord.Offset);

				if (texCoord != null)
				{
					var vector3 = texCoord.Source.GetVector3((ulong)indices[index1]);
					GL.TexCoord3(vector3.X,1.0-vector3.Y,vector3.Z);
				}
				GL.Vertex3(EvalPosition(i,positions));
			}

			End();
		}

		public Vector3 EvalPosition(ulong i)
		{
			return EvalPosition(i, this);
		}
		public Vector3 EvalPosition(ulong i, IPositionSource positions)
		{
			var index0 = (i) * stride + vertex.Offset;
			return positions.Position((ulong)indices[index0]);
		}

		public Vector3 EvalUV(ulong i)
		{
			if (texCoord == null)
				return Vector3.Zero;
			var index1 = ((i) * stride + texCoord.Offset);
			var vector3 = texCoord.Source.GetVector3((ulong)indices[index1]);
			return new Vector3(vector3.X, 1.0f - vector3.Y, vector3.Z);
		}

		public Vector3 EvalTangent(ulong i)
		{
			if (tangent == null)
				return Vector3.Zero;
			var index1 = ((i) * stride + tangent.Offset);
			return tangent.Source.GetVector3((ulong)indices[index1]);
		}
		public Vector3 EvalBinormal(ulong i)
		{
			if (binormal == null)
				return Vector3.Zero;
			var index1 = ((i) * stride + binormal.Offset);
			return binormal.Source.GetVector3((ulong)indices[index1]);
		}
		public Vector3 EvalNormal(ulong i)
		{
			if (normal == null)
				return Vector3.Zero;
			var index1 = ((i) * stride + normal.Offset);
			return normal.Source.GetVector3((ulong)indices[index1]);
		}

		public ulong EvalWeightIndex(ulong i)
		{
			var index0 = (i) * stride + vertex.Offset;
			return (ulong)indices[index0];
		}
	}
}